// File generated from our OpenAPI spec by Stainless.

package com.openai.models.images

import com.fasterxml.jackson.annotation.JsonAnyGetter
import com.fasterxml.jackson.annotation.JsonAnySetter
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty
import com.openai.core.ExcludeMissing
import com.openai.core.JsonField
import com.openai.core.JsonMissing
import com.openai.core.JsonValue
import com.openai.errors.OpenAIInvalidDataException
import java.util.Collections
import java.util.Objects
import java.util.Optional

/** Represents the content or the URL of an image generated by the OpenAI API. */
class Image
private constructor(
    private val b64Json: JsonField<String>,
    private val revisedPrompt: JsonField<String>,
    private val url: JsonField<String>,
    private val additionalProperties: MutableMap<String, JsonValue>,
) {

    @JsonCreator
    private constructor(
        @JsonProperty("b64_json") @ExcludeMissing b64Json: JsonField<String> = JsonMissing.of(),
        @JsonProperty("revised_prompt")
        @ExcludeMissing
        revisedPrompt: JsonField<String> = JsonMissing.of(),
        @JsonProperty("url") @ExcludeMissing url: JsonField<String> = JsonMissing.of(),
    ) : this(b64Json, revisedPrompt, url, mutableMapOf())

    /**
     * The base64-encoded JSON of the generated image. Default value for `gpt-image-1`, and only
     * present if `response_format` is set to `b64_json` for `dall-e-2` and `dall-e-3`.
     *
     * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the
     *   server responded with an unexpected value).
     */
    fun b64Json(): Optional<String> = b64Json.getOptional("b64_json")

    /**
     * For `dall-e-3` only, the revised prompt that was used to generate the image.
     *
     * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the
     *   server responded with an unexpected value).
     */
    fun revisedPrompt(): Optional<String> = revisedPrompt.getOptional("revised_prompt")

    /**
     * When using `dall-e-2` or `dall-e-3`, the URL of the generated image if `response_format` is
     * set to `url` (default value). Unsupported for `gpt-image-1`.
     *
     * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the
     *   server responded with an unexpected value).
     */
    fun url(): Optional<String> = url.getOptional("url")

    /**
     * Returns the raw JSON value of [b64Json].
     *
     * Unlike [b64Json], this method doesn't throw if the JSON field has an unexpected type.
     */
    @JsonProperty("b64_json") @ExcludeMissing fun _b64Json(): JsonField<String> = b64Json

    /**
     * Returns the raw JSON value of [revisedPrompt].
     *
     * Unlike [revisedPrompt], this method doesn't throw if the JSON field has an unexpected type.
     */
    @JsonProperty("revised_prompt")
    @ExcludeMissing
    fun _revisedPrompt(): JsonField<String> = revisedPrompt

    /**
     * Returns the raw JSON value of [url].
     *
     * Unlike [url], this method doesn't throw if the JSON field has an unexpected type.
     */
    @JsonProperty("url") @ExcludeMissing fun _url(): JsonField<String> = url

    @JsonAnySetter
    private fun putAdditionalProperty(key: String, value: JsonValue) {
        additionalProperties.put(key, value)
    }

    @JsonAnyGetter
    @ExcludeMissing
    fun _additionalProperties(): Map<String, JsonValue> =
        Collections.unmodifiableMap(additionalProperties)

    fun toBuilder() = Builder().from(this)

    companion object {

        /** Returns a mutable builder for constructing an instance of [Image]. */
        @JvmStatic fun builder() = Builder()
    }

    /** A builder for [Image]. */
    class Builder internal constructor() {

        private var b64Json: JsonField<String> = JsonMissing.of()
        private var revisedPrompt: JsonField<String> = JsonMissing.of()
        private var url: JsonField<String> = JsonMissing.of()
        private var additionalProperties: MutableMap<String, JsonValue> = mutableMapOf()

        @JvmSynthetic
        internal fun from(image: Image) = apply {
            b64Json = image.b64Json
            revisedPrompt = image.revisedPrompt
            url = image.url
            additionalProperties = image.additionalProperties.toMutableMap()
        }

        /**
         * The base64-encoded JSON of the generated image. Default value for `gpt-image-1`, and only
         * present if `response_format` is set to `b64_json` for `dall-e-2` and `dall-e-3`.
         */
        fun b64Json(b64Json: String) = b64Json(JsonField.of(b64Json))

        /**
         * Sets [Builder.b64Json] to an arbitrary JSON value.
         *
         * You should usually call [Builder.b64Json] with a well-typed [String] value instead. This
         * method is primarily for setting the field to an undocumented or not yet supported value.
         */
        fun b64Json(b64Json: JsonField<String>) = apply { this.b64Json = b64Json }

        /** For `dall-e-3` only, the revised prompt that was used to generate the image. */
        fun revisedPrompt(revisedPrompt: String) = revisedPrompt(JsonField.of(revisedPrompt))

        /**
         * Sets [Builder.revisedPrompt] to an arbitrary JSON value.
         *
         * You should usually call [Builder.revisedPrompt] with a well-typed [String] value instead.
         * This method is primarily for setting the field to an undocumented or not yet supported
         * value.
         */
        fun revisedPrompt(revisedPrompt: JsonField<String>) = apply {
            this.revisedPrompt = revisedPrompt
        }

        /**
         * When using `dall-e-2` or `dall-e-3`, the URL of the generated image if `response_format`
         * is set to `url` (default value). Unsupported for `gpt-image-1`.
         */
        fun url(url: String) = url(JsonField.of(url))

        /**
         * Sets [Builder.url] to an arbitrary JSON value.
         *
         * You should usually call [Builder.url] with a well-typed [String] value instead. This
         * method is primarily for setting the field to an undocumented or not yet supported value.
         */
        fun url(url: JsonField<String>) = apply { this.url = url }

        fun additionalProperties(additionalProperties: Map<String, JsonValue>) = apply {
            this.additionalProperties.clear()
            putAllAdditionalProperties(additionalProperties)
        }

        fun putAdditionalProperty(key: String, value: JsonValue) = apply {
            additionalProperties.put(key, value)
        }

        fun putAllAdditionalProperties(additionalProperties: Map<String, JsonValue>) = apply {
            this.additionalProperties.putAll(additionalProperties)
        }

        fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) }

        fun removeAllAdditionalProperties(keys: Set<String>) = apply {
            keys.forEach(::removeAdditionalProperty)
        }

        /**
         * Returns an immutable instance of [Image].
         *
         * Further updates to this [Builder] will not mutate the returned instance.
         */
        fun build(): Image = Image(b64Json, revisedPrompt, url, additionalProperties.toMutableMap())
    }

    private var validated: Boolean = false

    fun validate(): Image = apply {
        if (validated) {
            return@apply
        }

        b64Json()
        revisedPrompt()
        url()
        validated = true
    }

    fun isValid(): Boolean =
        try {
            validate()
            true
        } catch (e: OpenAIInvalidDataException) {
            false
        }

    /**
     * Returns a score indicating how many valid values are contained in this object recursively.
     *
     * Used for best match union deserialization.
     */
    @JvmSynthetic
    internal fun validity(): Int =
        (if (b64Json.asKnown().isPresent) 1 else 0) +
            (if (revisedPrompt.asKnown().isPresent) 1 else 0) +
            (if (url.asKnown().isPresent) 1 else 0)

    override fun equals(other: Any?): Boolean {
        if (this === other) {
            return true
        }

        return other is Image &&
            b64Json == other.b64Json &&
            revisedPrompt == other.revisedPrompt &&
            url == other.url &&
            additionalProperties == other.additionalProperties
    }

    private val hashCode: Int by lazy {
        Objects.hash(b64Json, revisedPrompt, url, additionalProperties)
    }

    override fun hashCode(): Int = hashCode

    override fun toString() =
        "Image{b64Json=$b64Json, revisedPrompt=$revisedPrompt, url=$url, additionalProperties=$additionalProperties}"
}
